package com.prj.ufdm.demo.tutorial.thread
;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Semaphore(信号量)的使用
  *   应用场景：同时最多可以三个线程同时操作，有20个线程等待操作
 * @author Administrator
 *
 */
public class TestSemaphoreApp {

	public static void main(String[] args) {
		
		TSResourceManage resourceManage = new TSResourceManage();  
        
        for (int i = 0; i < 5; i++) {  
        	final int userId = i;
            new Thread(new Runnable() {
				@Override
				public void run() {
			       System.out.print("userId:"+userId+"准备使用资源...\n");
			       resourceManage.useResource(userId);  
			       System.out.print("userId:"+userId+"使用资源完毕...\n");  					
				}
            }).start();
        }  
	}

}


class TSResourceManage {
	
	private final int poolSize = 2;
	private final Semaphore semaphore;
    private boolean resourceArray[];
    private final ReentrantLock lock;
    
    public TSResourceManage() {  
        this.resourceArray = new boolean[poolSize];    //存放可用状态  
        this.semaphore = new Semaphore(poolSize,true); //控制 poolSize 个共享资源的使用，使用先进先出的公平模式进行共享;公平模式的信号量，先来的先获得信号量  
        this.lock = new ReentrantLock(true);           //公平模式的锁，先来的先选  
        for(int i=0 ;i<poolSize; i++){  
            resourceArray[i] = true;//初始化为资源可用的情况  
        }  
    } 
    
    public void useResource(int userId){  
        try{  
            semaphore.acquire();  
            int id = getResourceId();//占到一个坑  
            System.out.print("userId:"+userId+"正在使用资源，资源id:"+id+"\n");  
            Thread.sleep(5000);//do something，相当于于使用资源  
            resourceArray[id] = true;//释放资源
        }catch (InterruptedException e){  
            e.printStackTrace();  
        }finally {  
            semaphore.release();//释放信号量，计数器加1  
        }  
    }
    
    private int getResourceId(){  
        int id = -1;  
        try {  
            lock.lock();
            for(int i=0; i<poolSize; i++){
                if(resourceArray[i]){  
                    resourceArray[i] = false;  
                    id = i;  
                    break;  
                }  
            }  
        }catch (Exception e){  
            e.printStackTrace();  
        }finally {  
            lock.unlock();  
        }  
        return id;  
    }  
	
}
